#ifndef _XDGEPOLL_HPP_
#define _XDGEPOLL_HPP_

#include <iostream>
#include <vector>

// ======================= Linux/POSIX 平台所需的头文件 =======================
#include <sys/epoll.h>   // epoll 核心头文件
#include <unistd.h>      // 适用于 close()
#include <stdexcept>     // 适用于 std::runtime_error
#include <cstring>       // 适用于 memset


namespace xdg
{

class Epoll
{
/***************************************构造/析构函数****************************************/
public:
    /**
     * @brief 构造函数, 创建一个 epoll 实例。
     * @param max_events epoll_wait 一次最多能处理的事件数
     */
    Epoll(int max_events = 1024);

    // 禁止拷贝、赋值、移动
    Epoll(const Epoll&) = delete;
    Epoll& operator=(const Epoll&) = delete;
    Epoll(Epoll&&) = delete;
    Epoll& operator=(Epoll&&) = delete;

    /**
     * @brief 析构函数, 自动关闭 epoll 文件描述符。
     */
    ~Epoll();

/*************************************** Epoll 底层封装接口 ****************************************/
public:
    //================================================================================================
    // 1. Epoll 实例生命周期 (Lifecycle)
    //================================================================================================

    /**
     * @brief 创建一个新的 epoll 实例 (构造函数已自动调用)。
     * @param againCreate 如果 epoll 文件描述符已经存在, 是否再次创建 (true: 创建新的, false: 使用已有的)。
     * @return 成功返回 epoll 文件描述符, 失败返回-1。
     */
    int createEpoll(bool againCreate = false);

    /**
     * @brief 关闭 epoll 实例 (析构函数已自动调用)。
     * @return 成功返回0, 失败返回-1。
     */
    int closeEpoll();

    //================================================================================================
    // 2. 事件注册与控制 (Control Operations)
    //================================================================================================

    /**
     * @brief 向 epoll 实例中添加一个新的文件描述符以进行监听。
     * @param fd 要添加的文件描述符 (例如 socket fd)。
     * @param events 要监听的事件组合 (例如 EPOLLIN | EPOLLET)。
     * @return 成功返回0, 失败返回-1。
     */
    int addSocket(int fd, uint32_t events);

    /**
     * @brief 修改 epoll 实例中已存在的文件描述符的监听事件。
     * @param fd 要修改的文件描述符。
     * @param events 新的事件组合。
     * @return 成功返回0, 失败返回-1。
     */
    int modifySocket(int fd, uint32_t events);

    /**
     * @brief 从 epoll 实例中移除一个文件描述符, 不再对其进行监听。
     * @param fd 要移除的文件描述符。
     * @return 成功返回0, 失败返回-1。
     */
    int deleteSocket(int fd);

    //================================================================================================
    // 3. 事件等待与获取 (Event Polling)
    //================================================================================================

    /**
     * @brief 等待已注册的文件描述符上发生事件。
     * @param timeout_ms 超时时间(毫秒)。-1 表示无限期阻塞; 0 表示立即返回。
     * @return 成功时返回发生事件的文件描述符数量; 超时返回0; 失败返回-1。
     */
    int wait(int timeout_ms = -1);

    /**
     * @brief 在 wait() 返回后, 获取指定索引处的 epoll 事件结构体。
     * @param index 事件数组的索引 (必须小于 wait() 的返回值)。
     * @return 指向 epoll_event 结构体的指针, 如果索引无效则返回 nullptr。
     */
    struct epoll_event* getEvent(int index);

    /**
     * @brief (便捷函数) 在 wait() 返回后, 获取指定索引处事件对应的文件描述符。
     * @param index 事件数组的索引。
     * @return 文件描述符, 如果索引无效则返回-1。
     */
    int getEventFd(int index);

    /**
     * @brief (便捷函数) 在 wait() 返回后, 获取指定索引处事件的事件类型掩码。
     * @param index 事件数组的索引。
     * @return 事件类型掩码 (如 EPOLLIN, EPOLLOUT), 如果索引无效则返回0。
     */
    uint32_t getEvents(int index);



/****************************************私有成员变量****************************************/
private:
    int m_epoll_fd;     // epoll_create1() 返回的文件描述符
    int m_max_events;   // 一次 wait 最多处理的事件数量
    
    std::vector<struct epoll_event> m_ready_events; // 用于存储 epoll_wait() 返回的就绪事件的缓冲区
    int m_ready_event_count; // 保存 wait() 返回的事件数量
};


// ================================================================================
// =================== 以下是所有成员函数的 inline 实现 ===========================
// ================================================================================


/*************************************** 构造/析构函数 ****************************************/

inline Epoll::Epoll(int max_events)
    : m_epoll_fd(-1),      // 初始化 epoll fd 为无效值
      m_max_events(max_events), // 设置最大事件数
      m_ready_events(max_events), // 根据最大事件数预分配事件数组大小
      m_ready_event_count(0)
{
    // 在构造时直接创建 epoll 实例
    createEpoll();
}

inline Epoll::~Epoll()
{
    // 在析构时自动关闭 epoll 实例, 释放资源
    closeEpoll();
}

/*************************************** Epoll 底层封装接口 ****************************************/

//================================================================================================
// 1. Epoll 实例生命周期
//================================================================================================

// 创建 epoll 实例，返回 epoll_create() 的实际返回值
inline int Epoll::createEpoll(bool againCreate)
{
    // true: 创建新的, false: 使用已有的
    if (m_epoll_fd != -1) {
        if (!againCreate) {
            return m_epoll_fd;
        }
        closeEpoll();
    }
    
    // 调用 epoll_create1() 创建 epoll 实例。
    m_epoll_fd = epoll_create1(0);

    if (m_epoll_fd == -1) {
        // 在库代码中, 抛出异常通常比直接退出更好
        throw std::runtime_error("epoll_create1 failed");
    }
    return m_epoll_fd;
}

inline int Epoll::closeEpoll()
{
    int result = 0;
    if (m_epoll_fd != -1) {
        // 调用 ::close() 关闭 epoll 文件描述符
        result = ::close(m_epoll_fd);
        // 重置为无效值, 防止重复关闭
        m_epoll_fd = -1;
    }
    return result;
}

//================================================================================================
// 2. 事件注册与控制
//================================================================================================

inline int Epoll::addSocket(int fd, uint32_t events)
{
    if (m_epoll_fd == -1) { return -1; }
    struct epoll_event event;
    memset(&event, 0, sizeof(event)); // 清零结构体
    event.events = events;  // 设置要监听的事件
    event.data.fd = fd;     // 将文件描述符存入 data 成员

    // 调用 epoll_ctl() 将 fd 添加到 epoll 的监听集合中
    return epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, fd, &event);
}

inline int Epoll::modifySocket(int fd, uint32_t events)
{
    if (m_epoll_fd == -1) { return -1; }
    struct epoll_event event;
    memset(&event, 0, sizeof(event));
    event.events = events;
    event.data.fd = fd;

    // 调用 epoll_ctl() 修改 fd 对应的监听事件
    return epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, fd, &event);
}

inline int Epoll::deleteSocket(int fd)
{
    if (m_epoll_fd == -1) { return -1; }

    // 调用 epoll_ctl() 将 fd 从 epoll 的监听集合中移除。第四个参数 event 可以是 nullptr
    return epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
}

//================================================================================================
// 3. 事件等待与获取
//================================================================================================

inline int Epoll::wait(int timeout_ms)
{
    if (m_epoll_fd == -1) { return -1; }

    // 调用 epoll_wait() 等待事件发生
    // m_ready_events.data() 返回指向vector底层数组的指针
    // m_max_events 是我们期望处理的最大事件数
    // timeout_ms 是超时时间
    m_ready_event_count = epoll_wait(m_epoll_fd, m_ready_events.data(), m_max_events, timeout_ms);
    return m_ready_event_count;
}

inline struct epoll_event* Epoll::getEvent(int index)
{
    // 使用 m_ready_event_count 进行正确的边界检查
    if (index >= 0 && index < m_ready_event_count) {
        return &m_ready_events[index];
    }
    return nullptr;
}

inline int Epoll::getEventFd(int index)
{
    // 便捷函数, 直接获取文件描述符
    struct epoll_event* ev = getEvent(index);
    if (ev) {
        return ev->data.fd;
    }
    return -1;
}

inline uint32_t Epoll::getEvents(int index)
{
    // 便捷函数, 直接获取事件类型
    struct epoll_event* ev = getEvent(index);
    if (ev) {
        return ev->events;
    }
    return 0;
}

} // 结束 namespace xdg

#endif // _XDGEPOLLIO_HPP_
